﻿function Tower(imgRepository) {
  var imageRepository = imgRepository;
  var level;
  var loaded = false;
  
  this.isLoaded = function () {
    return loaded;
  }

  // Enumerations.
  var buildingTypes = {
    nothing: {value: 0                                            },
    destroy: {value: 1                                            },
    end:     {value: 2,           images: imageRepository.End},
    wall:    {value: 3, width: 1, images: imageRepository.Wall,  cost: 1,  energyRate: 1},
    tomb:    {value: 4, width: 2, images: imageRepository.Tomb,  cost: 150, energyRate: 2},
    focus:   {value: 5, width: 3, images: imageRepository.Focus, cost: 300, energyRate: 5}
  };

  // Constants.
  var buildHeight = 80;
  var buildWidth = 40;
  var towerOffsetY = 50;

  // State information.
  var buildMode = buildingTypes.nothing;
  var buildings = [[buildingTypes.tomb, buildingTypes.wall], [buildingTypes.wall]];
  var currentFloor = 0;
  var currentSegment = 1;
  
  // Canvas info.
  var canvasHeight;
  var canvasWidth;
  var canvasOffsetX;
  var canvasOffsetY;

  // TODO: Move to game object.
  this.energy = 100;
  this.energyRate = 8;
  this.levelCount = 1;

  this.keyPress = function (event, canvas, gameState) {
    switch (gameState) {
    case document.game.gameStates.build:
      var KeyID = event.keyCode;
      switch (KeyID) {
      case 49: // 1
        buildMode = buildingTypes.wall;
        break;
      case 50: // 2
        buildMode = buildingTypes.tomb;
        break;
      case 51: // 3
        buildMode = buildingTypes.focus;
        break;
      case 192: // `
        buildMode = buildingTypes.destroy;
        updateDestroyTarget();
        break;
      case 27: // Escape
        if (buildMode.building != undefined) {
          buildings[buildMode.prevFloor][buildMode.prevSegment] = buildMode.building;
        }

        buildMode = buildingTypes.nothing;
        return;
      default:
        $('div#debug').text(KeyID);
        return;
      }
      if (this.energy < buildMode.cost) {
        buildMode = buildingTypes.nothing;
        return;
      }
      var tower = this;
      break;
    }
  }

  // TODO: Move to game object.
  this.mouseMove = function (event) {
    var posX = event.pageX - canvasOffsetX;
    var posY = event.pageY - canvasOffsetY;
    currentSegment = posXToSegment(posX);
    currentFloor = posYToFloor(posY);
    $('div#debug').text(currentFloor + ' ' + currentSegment + ' ' + posX + ' ' + posY);
  }

  // TODO: Move to game object.
  this.mouseDown = function () {
    if (build(buildMode)) {
      if (buildMode != buildingTypes.destroy) {
        this.energyRate += buildMode.energyRate;
        this.energy -= buildMode.cost;
      }
      buildMode = buildingTypes.nothing;
    }
    if (checkLevel()) {
      this.levelCount++;
      level = LevelRepository(this.levelCount);
      if (level == undefined) {
        document.game.win();
      }
    }
  }

  var build = function () {
    switch (buildMode) {
    case buildingTypes.wall:
      var currentFloorSegments = buildings[currentFloor];
      var prevFloorSegments = buildings[currentFloor - 1];
      if (currentFloorSegments == undefined && prevFloorSegments != undefined) {
        buildings[currentFloor] = new Array(buildingTypes.wall);
        return true;
      } else if (currentFloor == 0 || (currentFloorSegments != undefined && currentFloorSegments.length < prevFloorSegments.length)) {
        currentFloorSegments.push(buildingTypes.wall);
        return true;
      }
      break;
    case buildingTypes.tomb:
      // Fall through.
    case buildingTypes.focus:
      var currentFloorSegments = buildings[currentFloor];
      if (currentFloorSegments != undefined) {
        var currentSegment = Math.max(0, Math.min(currentFloorSegments.length - buildMode.width, parseInt(currentSegment - (buildMode.width - 1) / 2)));
        if (checkBuildPlacement(buildMode, currentSegment)) {
            currentFloorSegments[currentSegment] = buildMode;
            return true;
        }
      }
      break;
    case buildingTypes.destroy:
      if (buildMode.building != undefined && buildMode.building != buildingTypes.wall) {
        this.energyRate -= buildMode.building.energyRate;
        this.energy += parseInt(buildMode.building.cost / 2);
        buildMode.building = undefined;
        return true;
      }
    }
    return false;
  }

  var updateDestroyTarget = function () {
    if (buildMode.building != undefined) {
      buildings[buildMode.prevFloor][buildMode.prevSegment] = buildMode.building;
    }

    if (buildings[currentFloor] != undefined && currentSegment < buildings[currentFloor].length) {
      var currentSegment = parseInt(currentSegment);
      for (var key in buildingTypes) {
        if (buildingTypes[key] != null) {
          var building = buildingTypes[key];
          for (var i = 0; i < building.width; i++) {
            if (buildings[currentFloor][currentSegment - i] == building) {
              buildMode.prevFloor = currentFloor;
              buildMode.prevSegment = currentSegment - i;
              buildMode.building = building;
              buildings[currentFloor][currentSegment - i] = buildingTypes.wall;
            }
          }
        }
      }
    } else {
      buildMode.building = undefined;
    }
  }

  var checkBuildPlacement = function (building, currentSegment) {
    var currentFloorSegments = buildings[currentFloor];
    if (currentSegment < 0 && currentSegment > currentFloorSegments.length - building.width + 1) {
      return false;
    }
    for (var i = 0; i < building.width; i++) {
      if (currentFloorSegments[currentSegment + i] != buildingTypes.wall) {
        return false;
      }
    }
    for (var key in buildingTypes) {
      if (buildingTypes[key] != null) {
        building = buildingTypes[key];
        for (var i = 1; i < building.width && i < currentSegment + 1; i++) {
          if (currentFloorSegments[currentSegment - i] == building) {
            return false;
          }
        }
      }
    }
    return true;
  }

  this.load = function (canvas) {
    canvasHeight = canvas.height;
    canvasWidth = canvas.width;
    canvasOffsetX = canvas.offsetLeft;
    canvasOffsetY = canvas.offsetTop;
    level = new LevelRepository(this.levelCount);
    loaded = true;
  }

  this.update = function (frameCount) {
    if (buildMode == buildingTypes.destroy) {
      updateDestroyTarget();
    }
  }

  this.updateEnergy = function () {
    this.energy += this.energyRate;
  }

  this.clearModes = function () {
    buildMode = buildingTypes.nothing;
  }

  var checkLevel = function () {
    for (var floor = 0; floor < level.length; floor++) {
      if (buildings[floor] == undefined || level[floor] > buildings[floor].length) {
        return false;
      }
    }
    return true;
  }

  this.draw = function (canvasContext, gameState) {
    drawTowerBackground(canvasContext);
    drawTower(canvasContext);
    drawTowerBuildings(canvasContext);
    if (gameState == document.game.gameStates.build) {
      drawBuildModeOverlay(canvasContext);
    }
  }

  var drawTowerBackground = function (canvasContext) {
    var posY = canvasHeight - towerOffsetY;
    for(var posX = 0; posX < canvas.width; posX += 50) {
      canvasContext.drawImage(imageRepository.Ground, posX, posY);
    }

    if (level != undefined) {
      for (var floor = 0; floor < level.length; floor++) {
        var segment = 0;
        for (segment = 0; segment < level[floor]; segment++) {
          canvasContext.drawImage(buildingTypes.wall.images[imageRepository.imageModes.semi], segmentToPosX(segment), floorToPosY(floor));
        }
        canvasContext.drawImage(buildingTypes.end.images[imageRepository.imageModes.semi], segmentToPosX(segment), floorToPosY(floor) - 8);
      }
    }
  }

  drawTower = function (canvasContext) {
    for (var floor = 0; floor < buildings.length; floor++) {
      var segment = 0;
      for (segment = 0; segment < buildings[floor].length; segment++) {
        canvasContext.drawImage(buildingTypes.wall.images[imageRepository.imageModes.main], segmentToPosX(segment), floorToPosY(floor));
      }
      canvasContext.drawImage(buildingTypes.end.images[imageRepository.imageModes.main], segmentToPosX(segment), floorToPosY(floor) - 8);
    }
  }

  drawTowerBuildings = function (canvasContext) {
    for (var floor = 0; floor < buildings.length; floor++) {
      var segment = 0;
      var building = buildings[floor][segment];
      for (segment = 0; segment < buildings[floor].length; segment += building.width) {
        building = buildings[floor][segment];
        switch (building) {
        case buildingTypes.tomb:
          // Fall through.
        case buildingTypes.focus:
          var img = building.images[imageRepository.imageModes.main];
          canvasContext.drawImage(img, segmentToPosX(segment), floorToPosY(floor));
          break;
        }
      }
    }
  }

  drawBuildModeOverlay = function (canvasContext) {
    var posX = new Array();
    var posY = floorToPosY(currentFloor) + buildHeight * 2 / 3;
    switch (buildMode) {
    case buildingTypes.wall:
      var currentFloorSegments = buildings[currentFloor];
      var prevFloorSegments = buildings[currentFloor - 1];
      var segment = 0;
      if (currentFloorSegments == undefined && prevFloorSegments != undefined) {
      } else if (currentFloor == 0 || (currentFloorSegments != undefined && currentFloorSegments.length < prevFloorSegments.length)) {
        segment = currentFloorSegments.length;
      } else {
        break;
      }
      canvasContext.drawImage(buildingTypes.wall.images[imageRepository.imageModes.semi], segmentToPosX(segment), floorToPosY(currentFloor));
      canvasContext.drawImage(buildingTypes.end.images[imageRepository.imageModes.semi], segmentToPosX(segment + 1), floorToPosY(currentFloor) - 8);
      break;
    case buildingTypes.tomb:
      // Fall through.
    case buildingTypes.focus:
      var currentFloorSegments = buildings[currentFloor];
      if (currentFloorSegments != undefined) {
        var currentSegment = Math.max(0, Math.min(currentFloorSegments.length - buildMode.width, parseInt(currentSegment - (buildMode.width - 1) / 2)));
        if (checkBuildPlacement(buildMode, currentSegment)) {
          var img = buildMode.images[imageRepository.imageModes.semi];
          canvasContext.drawImage(img, segmentToPosX(currentSegment), floorToPosY(currentFloor));
        }
      }
      break;
    case buildingTypes.destroy:
      updateDestroyTarget();
      if (buildMode.building != undefined && buildMode.building != buildingTypes.wall) {
        var img = buildMode.building.images[imageRepository.imageModes.semi];
        canvasContext.drawImage(img, segmentToPosX(buildMode.prevSegment), floorToPosY(buildMode.prevFloor));
      }
      break;
    }
  }

  var floorToPosY = function (floor) {
    return canvasHeight - buildHeight * (floor + 1) - 24 - towerOffsetY;
  }

  var segmentToPosX = function (segment) {
    return buildWidth * segment;
  }

  var posYToFloor = function (posY) {
    return parseInt((canvasHeight - posY - towerOffsetY) / buildHeight);
  }

  var posXToSegment = function (posX) {
    return posX / buildWidth;
  }
}